import { relationalStore, ValuesBucket } from "@kit.ArkData";
import { delay, FnContext, LogTag, Option, _appError2, _appInfo2 } from "CoffeeSdk";
import { Field, FieldType } from "./Field";
import { process } from "@kit.ArkTS";
import { gamePerformance } from "@kit.GameServiceKit";

export function processResultSet<T>(resultSet: relationalStore.ResultSet,
  processFn: (rowIndex: number, colNames: string[], typeNames: string[]) => boolean | void, close: boolean = true, c?: FnContext) {
  try {
    const rowCount = resultSet.rowCount;
    const colCount = resultSet.columnCount;
    _appInfo2(`readResultSet,row:${rowCount},col:${colCount}`, { c: c });
    if (rowCount <= 0) {
      _appError2(`rowcount is ${rowCount}`, { c: c });
      return;
    }
    let rowIndex = 0;
    const colNames: string[] = [];
    const typeNames: string[] = [];

    if (resultSet.goToFirstRow()) {
      for (let i = 0; i < colCount; i++) {
        const colName = resultSet.getColumnName(i);
        const colValue = resultSet.getValue(i);
        const type = typeof colValue;
        colNames.push(colName);
        typeNames.push(type);
      }
      let ret = processFn(rowIndex, colNames, typeNames);
      if (ret === false) {
        return;
      }
      rowIndex++;
      while (resultSet.goToNextRow()) {
        ret = processFn(rowIndex, colNames, typeNames);
        if (ret === false) {
          return;
        }
        rowIndex++;
      }
      _appInfo2(`read ${rowCount} entity`, { c: c });

    } else {
      _appError2(`got to first row failed`, { c: c })
    }
  } finally {
    if (close) {
      resultSet.close();
    }
  }

}


/**
 * 打印结果集合
 * @param resultSet
 * @param processFn
 * @returns
 */
export function getResultSetInfo(resultSet: relationalStore.ResultSet, c: Option<FnContext>): string {
  let string = '\r\n';
  const padLen = 15;
  processResultSet(resultSet, (rowIndex: number, colNames: string[], typeNames: string[]) => {
    let rowStr = `name:`.padEnd(5);
    if (rowIndex == 0) {
      for (let i = 0; i < resultSet.columnCount; i++) {
        const type = typeNames[i];
        const name = colNames[i]
        const title = `${name}|${type}`.padEnd(padLen);
        rowStr += `\t${title}`;
      }
      string += `${rowStr}\r\n`;
    }
    rowStr = `${rowIndex}:`.padEnd(5);
    for (let i = 0; i < resultSet.columnCount; i++) {
      const value = resultSet.getValue(i)?.toString().padEnd(padLen);
      rowStr += `\t${value}`;
    }
    string += `${rowStr}\r\n`;

    if (rowIndex == 90) {
      return false
    } else {
      return true
    }
  }, true, c);
  return string;
}


/**
 * 同步查询很多数据是否会卡死?
 * 查询和转换上w条数据会造成THREAD_BLOCK_6S 的闪退
 * 直接把一个函数改为异步,那么这个函数的1w次循环就都是异步了么?
 * @param resultSet 结果集
 * 结果集,一般都是一个二维数组,第一行是名称.第二行是具体数据.
 * @param rowIndex 为当前读的行数
 * @returns
 */
export function readResultSetSync(resultSet: relationalStore.ResultSet): ValuesBucket[] {
  _appInfo2(`read begin`)
  const buckets: ValuesBucket[] = [];
  processResultSet(resultSet, (rowIndex: number, colNames: string[]) => {
    const bucket: ValuesBucket = {};
    for (let i = 0; i < resultSet.columnCount; i++) {
      const name = colNames[i];
      const value = resultSet.getValue(i);
      //数据库中的bigint类型,不能直接传入.
      const type = typeof value;
      switch (type) {
        case "bigint":
          //TODO not surpport
          bucket[name] = 0;
          break;
        default:
          bucket[name] = value as number | string | Uint8Array;
      }
    }
    buckets.push(bucket);
  });
  _appInfo2(`read end`)
  return buckets;
}

/**
 * 打印resultSet
 * @param resultSet
 * @param c
 */
export function printResultSet(resultSet: relationalStore.ResultSet, c: FnContext) {
  const str = getResultSetInfo(resultSet, c);
  _appInfo2(str, { c: c });
}

/**
 * 根据fileds读取所有字段信息
 * @param resultSet
 * @param fieldInfo
 */
export function readOneEntityFromResultSet(resultSet: relationalStore.ResultSet,
  fields: Field[]): ValuesBucket {
  const bucket = {};
  for (let i = 0; i < fields.length; i++) {
    const field = fields[i];
    let value: relationalStore.ValueType = undefined;
    switch (field.type) {
      case FieldType.Int: {
        value = resultSet.getLong(i);
        break;
      }
      case FieldType.String: {
        value = resultSet.getString(i);
        break;
      }
    }
    bucket[field.name] = value;
  }
  return bucket;
}